
import { PluginOption } from "vite";
import path from 'path';
import dayjs from 'dayjs';
import fs from 'fs';
import { add, see, templateList } from "./fun";

/**
 * 基于vite的插件，监听‘modules’文件夹下的文件变化，自动生成模块字典
 */
export default function (): PluginOption[] {

    let t;

    return [{
        name: 'vite-create-module-dictionary',
        apply: 'serve',
        configureServer(server) {
            server.watcher.on('change', (filePath) => {
                filePath = filePath.replace(/\\/g, '/');
                const id = getModuleId(filePath)
                if (id && filePath.endsWith('src/modules/' + id + '/index.tsx')) {
                    clearTimeout(t); t = setTimeout(creacte, 1000);
                }
            });

            server.watcher.on('add', (filePath) => {
                filePath = filePath.replace(/\\/g, '/');
                const id = getModuleId(filePath)
                if (id && filePath.endsWith('src/modules/' + id + '/index.tsx')) {
                    clearTimeout(t); t = setTimeout(creacte, 1000);
                }
            });

            server.watcher.on('unlink', (filePath) => {
                filePath = filePath.replace(/\\/g, '/');
                const id = getModuleId(filePath)
                if (id && filePath.endsWith('src/modules/' + id + '/index.tsx')) {
                    clearTimeout(t); t = setTimeout(creacte, 1000);
                }
            });

            // 查看模块源码
            server.middlewares.use('/dev/module/see', see);

            // 模块模版列表
            server.middlewares.use('/dev/module/templateList', templateList)

            // 创建模块
            server.middlewares.use('/dev/module/add', add);

            // creacte().catch(console.error);
        },

        buildStart() {
            creacte().catch(console.error);
        },
    }]
}

/** 创建字典文件 */
async function creacte() {
    console.log(`${dayjs().format('HH:mm:ss')} [vite-create-module-dictionary] create module dictionary`)
    try {
        /** 模块列表 */
        const modules = getDirectories(path.join(__dirname, '../../src/modules'))
            .map(e => {
                const id = path.basename(e);
                const component = `lazy(() => import('./${id}'))`
                const modulesStr = fs.readFileSync(path.join(e, 'index.tsx'), 'utf-8');
                const title = getProperty(modulesStr, 'title');
                const icon = getProperty(modulesStr, 'icon');
                const tag = getProperty(modulesStr, 'tag');
                const key = getProperty(modulesStr, 'key');
                const description = getProperty(modulesStr, 'description');
                const deprecated = getProperty(modulesStr, 'deprecated');
                return `
    ['${id}',{
        key: '${key}',
        id: '${id}',
        title: '${title || id}',
        icon: ${icon ? `'${icon}'` : 'null'},
        tag: ${tag ? `'${tag}'` : 'null'},
        deprecated: ${deprecated ? `'${deprecated}'` : 'null'},
        description: ${description ? `'${description}'` : 'null'},
        component: ${component},
    }]`
            })

        /** 字典模版 */
        let template = fs.readFileSync(path.join(__dirname, 'index.template'), 'utf-8');
        template = template.replace('{{#modules}}', modules.join(',\n'));
        fs.writeFileSync(path.join(__dirname, '../../src/modules/index.ts'), template);
    } catch (error) {
        console.error(error);
    }
    console.log(`${dayjs().format('HH:mm:ss')} [vite-create-module-dictionary] create module dictionary success`)
}

function getDirectories(source: string): string[] {
    return fs.readdirSync(source, { withFileTypes: true })
        .filter(dirent => dirent.isDirectory())
        .map(dirent => path.join(source, dirent.name));
}

function getProperty(str: string, key: string): string | null {
    const match = str.match(new RegExp(`@${key}\\s+(.*?)\\s`, "s"));
    return match ? match[1] : null;
}

/** 获取模块id */
function getModuleId(filePath: string) {
    if (!filePath.includes('src/modules')) return undefined;
    return filePath.split('src/modules/')[1].split('/')[0];
}